#pragma once
#include <functional>
#include <semaphore>
#include <memory>

#include <boost/lockfree/queue.hpp>

#include "setting.hpp"
#include "format.hpp"
#include "output.hpp"

namespace my_log
{
	using dura = std::chrono::milliseconds;

	// 日志器基类
	// 日志器使用CRTP静态多态设计
	// 因此禁止使用delete销毁基类指针，请使用destroy()
	template<typename logger_type>
	class logger_base
	{
	protected:
		logger_base(const std::string& name, log_level::value min_lv, const flush_strategy::strategy_base& strategy)
			: _name(name)
			, _status(0)
			, _min_output_level(min_lv)
			, _pattern_table(my_log::log_format_setting::getInstance())
			, _f(_status, strategy._level_times)
		{}

		logger_base(const std::string& name, log_level::value min_lv, const flush_strategy::strategy_base& strategy, 
			std::vector<std::string>&& format_str_arr, std::vector<std::vector<output_t>>&& outputs_arr)
			: _name(name)
			, _status(0)
			, _min_output_level(min_lv)
			, _format_str_arr(std::move(format_str_arr))
			, _outputs_arr(std::move(outputs_arr))
			, _pattern_table(my_log::log_format_setting::getInstance())
			, _f(_status, strategy._level_times)
		{}

		logger_base(const logger_base&) = delete;
		logger_base(logger_base&&) = delete;
	public:
		// 基类销毁函数
		// 使用delete销毁基类指针将造成内存泄漏
		// 派生类必须实现其调用的函数
		void destroy() const
		{
			static_cast<const logger_type*>(this)->destroy_impl();
		}

		// 添加日志格式与输出方式
		// 派生类必须实现其调用的函数
		void addFmtStrAndOutput(const std::string& name, std::vector<output_t>&& outputs)
		{
			if (_status != 0)
			{
				throw log_error{ "logger_base::addFmtStrAndOutput: logger is working, cannot add" };
			}
			_format_str_arr.push_back(_pattern_table.at(name));
			_outputs_arr.emplace_back(std::move(outputs));
			for (auto& output : _outputs_arr[_outputs_arr.size() - 1])
			{
				_f.addTimer(&output);
			}
			static_cast<logger_type*>(this)->addFmtStrAndOutput_impl();
		}

		// 日志器启动函数
		// 派生类必须实现其调用的函数
		void start()
		{
			if (_status.load(std::memory_order_relaxed) != 0)
			{
				throw log_error{ "logger_base::start: logger has started" };
			}
			_status.store(1, std::memory_order_relaxed);
			static_cast<logger_type*>(this)->start_impl();
		}

		// debug等级日志
		void debug(const std::source_location& loc, const std::string& pay_load)
		{
			if (logCheck(log_level::value::DEBUG))
			{
				logging(log_message{ _name, loc.file_name(), loc.line(), loc.column(), log_level::value::DEBUG, pay_load });
			}
		}

		// info等级日志
		void info(const std::source_location& loc, const std::string& pay_load)
		{
			if (logCheck(log_level::value::INFO))
			{
				logging(log_message{ _name, loc.file_name(), loc.line(), loc.column(), log_level::value::INFO, pay_load });
			}
		}

		// warn等级日志
		void warn(const std::source_location& loc, const std::string& pay_load)
		{
			if (logCheck(log_level::value::WARN))
			{
				logging(log_message{ _name, loc.file_name(), loc.line(), loc.column(), log_level::value::WARN, pay_load });
			}
		}

		// error等级日志
		void error(const std::source_location& loc, const std::string& pay_load)
		{
			if (logCheck(log_level::value::ERR))
			{
				logging(log_message{ _name, loc.file_name(), loc.line(), loc.column(), log_level::value::ERR, pay_load });
			}
		}

		// fatal等级日志
		void fatal(const std::source_location& loc, const std::string& pay_load)
		{
			if (logCheck(log_level::value::FATAL))
			{
				logging(log_message{ _name, loc.file_name(), loc.line(), loc.column(), log_level::value::FATAL, pay_load });
			}
		}

		// 为防止因当前日志等级低于最低日志等级所造成的格式化字符串开销, 创造此变体
		template<class... Args>
		void debug(const std::source_location& loc, const std::string& pat, Args... args)
		{
			if (logCheck(log_level::value::DEBUG))
			{
				logging(log_message{ _name, loc.file_name(), loc.line(), loc.column(), log_level::value::DEBUG, 
					std::vformat(pat, std::make_format_args(args...)) });
			}
		}

		// 为防止因当前日志等级低于最低日志等级所造成的格式化字符串开销, 创造此变体
		template<class... Args>
		void info(const std::source_location& loc, const std::string& pat, Args... args)
		{
			if (logCheck(log_level::value::INFO))
			{
				logging(log_message{ _name, loc.file_name(), loc.line(), loc.column(), log_level::value::INFO, 
					std::vformat(pat, std::make_format_args(args...)) });
			}
		}

		// 为防止因当前日志等级低于最低日志等级所造成的格式化字符串开销, 创造此变体
		template<class... Args>
		void warn(const std::source_location& loc, const std::string& pat, Args... args)
		{
			if (logCheck(log_level::value::WARN))
			{
				logging(log_message{ _name, loc.file_name(), loc.line(), loc.column(), log_level::value::WARN, 
					std::vformat(pat, std::make_format_args(args...)) });
			}
		}

		// 为防止因当前日志等级低于最低日志等级所造成的格式化字符串开销, 创造此变体
		template<class... Args>
		void error(const std::source_location& loc, const std::string& pat, Args... args)
		{
			if (logCheck(log_level::value::ERR))
			{
				logging(log_message{ _name, loc.file_name(), loc.line(), loc.column(), log_level::value::ERR, 
					std::vformat(pat, std::make_format_args(args...)) });
			}
		}

		// 为防止因当前日志等级低于最低日志等级所造成的格式化字符串开销, 创造此变体
		template<class... Args>
		void fatal(const std::source_location& loc, const std::string& pat, Args... args)
		{
			if (logCheck(log_level::value::FATAL))
			{
				logging(log_message{ _name, loc.file_name(), loc.line(), loc.column(), log_level::value::FATAL, 
					std::vformat(pat, std::make_format_args(args...)) });
			}
		}

		// 优化配置一
		// 抛弃与C流的同步
		// 使用该功能将出现和C流的数据竞争
		// 提升screen输出性能，小幅提升文件流性能
		void disableSyncWithStdio()
		{
			if (_status != 0)
			{
				throw log_error{ "logger_base::disableSyncWithStdio: logger has started, connot change sync" };
			}
			std::ios_base::sync_with_stdio(false);
		}

		// 优化配置二
		// 解绑输出流
		// 使用该功能可能导致输入输出混乱
		// 提升非交互式程序性能
		void untiedStream()
		{
			if (_status != 0)
			{
				throw log_error{ "logger_base::disableSyncWithStdio: logger has started, connot untied stream" };
			}
			std::cin.tie(nullptr);
		}
	private:
		// 日志落地函数
		// 派生类必须实现其调用的函数
		void logging(const log_message& msg)
		{
			static_cast<logger_type*>(this)->logging(std::move(msg));
		}

		// 检验日志器是否启动
		bool logCheck(log_level::value lv)
		{
			if (_status.load(std::memory_order_relaxed) == 0)
			{
				throw log_error{ "logger_base::logCheck: logger hasn't started" };
			}
			return lv >= _min_output_level;
		}
	protected:
		// 日志器名称
		std::string _name;
		// 日志器状态
		// 0: 关闭
		// 1: 启动
		// 2: 等待退出
		std::atomic<size_t> _status;
		// 最低日志输出等级
		std::atomic<log_level::value> _min_output_level;
		// 日志格式集合
		std::vector<std::string> _format_str_arr;
		// 落地方式集合
		std::vector<std::vector<output_t>> _outputs_arr;
		// 日志格式管理模块
		log_format_setting& _pattern_table;
		// 缓冲区刷新器
		flusher _f;
	};

	// 同步型日志器
	class sync_logger : public logger_base<sync_logger>
	{
		friend class logger_base<sync_logger>;
	public:
		sync_logger(const std::string& name, log_level::value min_lv, flush_strategy::strategy_base strategy);
		sync_logger(const std::string& name, log_level::value min_lv, flush_strategy::strategy_base strategy, 
			std::vector<std::string>&& format_str_arr, std::vector<std::vector<output_t>>&& output_arr);
		~sync_logger();
	private:
		// 派生类销毁函数
		void destroy_impl() const;

		// 客制化后加工函数
		void addFmtStrAndOutput_impl() {}

		// 派生类启动函数
		void start_impl() {}

		// 派生类日志落地函数
		void logging(const log_message& msg);
	};

	// 异步型日志器
	class async_logger : public logger_base<async_logger>
	{
		friend class logger_base<async_logger>;
	public:
		// 消息缓存器
		class msg_buffer
		{
		public:
			msg_buffer(size_t len = MAX_FORMATTED_STR_LEN);
			msg_buffer(const msg_buffer& other) = delete;
			msg_buffer(msg_buffer&& other) noexcept;
			// 写入日志
			void write(const log_message& msg, const std::string& fmt_form, size_t index);

			// 读取日志
			std::string_view read() const noexcept;

			// 获取日志等级
			std::string_view getLevel(int) const noexcept;

			// 获取日志等级
			log_level::value getLevel() const noexcept;

			// 获取样式&输出方式序号
			size_t getIndex() const noexcept;

			// 重置缓冲区
			void reset() noexcept;
		private:
			// 日志缓存区
			std::vector<char> _buffer;
			// 日志等级
			log_level::value _level;
			// 日志长度
			size_t _len;
			// 样式&输出方式序号
			size_t _index;
		};

		class msg_buffer_pool
		{
		public:
			msg_buffer_pool(size_t max_node);
			~msg_buffer_pool();

			// 申请节点
			bool allocate(std::unique_ptr<msg_buffer>& ret_ptr);

			// 回收节点
			void recycle(std::unique_ptr<msg_buffer>&& buf_ptr);

			// 节点容量是否达到上限
			bool isFull() noexcept;

			// 获取借出节点数量
			size_t getOutterCount() noexcept;
		private:
			// 队列最大节点数
			const size_t _max_node;
			// 总节点数
			size_t _total_node_count;
			// 已借出节点数
			size_t _outter_node_count;
			// 无锁队列
			boost::lockfree::queue<msg_buffer*> _node_queue;
		};
	public:
		async_logger(const std::string& name, log_level::value min_lv, flush_strategy::strategy_base strategy);
		async_logger(const std::string& name, log_level::value min_lv, flush_strategy::strategy_base strategy, 
			std::vector<std::string>&& format_str_arr, std::vector<std::vector<output_t>>&& output_arr);
		~async_logger();
	private:
		// 派生类销毁函数
		void destroy_impl() const;

		// 派生类添加日志格式与输出方式函数
		void addFmtStrAndOutput_impl();

		// 派生类启动函数
		void start_impl();

		// 派生类日志输出函数
		void logging(const log_message& msg);

		// 异步日志器落地线程入口
		void entry();
	private:
		// 无锁队列
		boost::lockfree::queue<msg_buffer*> _transfer_queue;
		// 日志节点池
		msg_buffer_pool _pool;
		// 启动间隔
		dura _startup_duration;
		// 最低启动日志数
		size_t _startup_count;
		// 生产者等待体
		std::binary_semaphore _producer_waiter;
		// 消费者条件变量
		std::condition_variable _consumer_cond;
		// 消费者线程锁
		std::mutex _consumer_ctrl;
		// 日志落地线程
		std::thread _worker;
	};
}